﻿using System;
using System.Net.Sockets;
using System.Collections.Generic;
namespace GX
{
    public class NetReciever
    {
        private readonly System.Object _recieveLocker = new object();
        private readonly System.Object _exeLocker = new object();

        private Queue<PackageIn> _pkgQueue = new Queue<PackageIn>();
        private NetManager _netMgr;
        private Socket _sock;

        private readonly byte[] _recvBuffer = new byte[NetConfig.BUFFER_SIZE];

        private int _readOffset = 0;
        private int _dataLeft = 0;
        private int _pkgBodyLen = -1;
        private byte[] _headBytes = new byte[2];
        public void Setup(NetManager netMgr, Socket sock)
        {
            _netMgr = netMgr;
            _sock = sock;
        }
        public void Recieve()
        {
            lock (_recieveLocker)
            {
                if (null == _netMgr)
                {
                    return;
                }
                if (null == _sock)
                {
                    return;
                }
                if (null == _recvBuffer)
                {
                    return;
                }
                try
                {
                    DoRecieve();
                }
                catch (ObjectDisposedException e)//本地已经关闭了socket?
                {
                    if (null != _netMgr && null != _netMgr.onClose)
                    {
                        _netMgr.onClose(_netMgr);
                    }
                }
                catch (Exception e)//对方网络有问题?
                {
                    if (null != _netMgr && null != _netMgr.onError)
                    {
                        _netMgr.onError(_netMgr, e.Message);
                    }
                }
            }

        }

        private void DoRecieve()
        {

            int bytesAvailable = Math.Min(_sock.Available, NetConfig.BUFFER_SIZE - _dataLeft);
            if (bytesAvailable > 0)
            {
                int numRecieved = _sock.Receive(_recvBuffer, _dataLeft, bytesAvailable, SocketFlags.None);
                _dataLeft += numRecieved;
                ReadPackage();
            }
        }
        private void ReadPackage()
        {
            this._readOffset = 0;

            while (_dataLeft >= NetConfig.PKG_SIZE_MIN)
            {
                //还没读到包的长度
                if (_pkgBodyLen < 0)
                {
                    //协议体的长度
                    _headBytes[0] = _recvBuffer[_readOffset + 1];
                    _headBytes[1] = _recvBuffer[_readOffset];
                    _pkgBodyLen = BitConverter.ToInt16(_headBytes, 0);
                    _dataLeft -= NetConfig.HEAD_SIZE;
                    _readOffset += NetConfig.HEAD_SIZE;
                }
                else
                {
                    /**无法凑成一条完整数据包
                    */
                    if (_dataLeft < _pkgBodyLen)
                    {
                        break;
                    }
                    else
                    {
                        this.ParsePackage(_recvBuffer, _readOffset, _pkgBodyLen);

                        _dataLeft -= _pkgBodyLen;
                        _readOffset += _pkgBodyLen;
                        _pkgBodyLen = -1;
                    }
                }
            }
            /**剩余不足一条完整数据包的内容，复制前移到起始位置
             */
            if (_dataLeft > 0)
            {
                Buffer.BlockCopy(_recvBuffer, _readOffset, _recvBuffer, 0, _dataLeft);
            }
            _readOffset = 0;
        }
        private void ParsePackage(byte[] src, int offset, int len)
        {
            PackageIn pkg = new PackageIn(len);
            pkg.InitHead(src, offset, len);
            _pkgQueue.Enqueue(pkg);
        }
        public void ExePackage()
        {
            lock (_exeLocker)
            {
                int numFinished = 0;
                while (numFinished <= NetConfig.PKG_PER_FRAME_MAX
                    && _pkgQueue.Count > 0)
                {
                    PackageIn pkg = _pkgQueue.Dequeue();
                    _netMgr.HandlePackage(pkg);
                    ++numFinished;
                }
            }
        }
    }//END CLASS
}